<?php
class AdminGroupGridField extends GridField {
	public function FieldHolder($properties = array()) {
		Requirements::css(THIRDPARTY_DIR . '/jquery-ui-themes/smoothness/jquery-ui.css');
		Requirements::css(FRAMEWORK_DIR . '/css/GridField.css');

		Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js');
		Requirements::javascript(FRAMEWORK_DIR . '/thirdparty/jquery-ui/jquery-ui.js');
		Requirements::javascript(THIRDPARTY_DIR . '/json-js/json2.js');
		Requirements::javascript(FRAMEWORK_DIR . '/javascript/i18n.js');
		Requirements::add_i18n_javascript(FRAMEWORK_DIR . '/javascript/lang');
		Requirements::javascript(THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js');
		Requirements::javascript(FRAMEWORK_DIR . '/javascript/GridField.js');

		// Get columns
		$columns = $this->getColumns();

		// Get data
		$list = $this->getManipulatedList();
		
		// Render headers, footers, etc
		$content = array(
			"before" => "",
			"after" => "",
			"header" => "",
			"footer" => "",
		);

		foreach($this->getComponents() as $item) {			
			if($item instanceof GridField_HTMLProvider) {
				$fragments = $item->getHTMLFragments($this);
				if($fragments) foreach($fragments as $k => $v) {
					$k = strtolower($k);
					if(!isset($content[$k])) $content[$k] = "";
					$content[$k] .= $v . "\n";
				}
			}
		}

		foreach($content as $k => $v) {
			$content[$k] = trim($v);
		}

		// Replace custom fragments and check which fragments are defined
		// Nested dependencies are handled by deferring the rendering of any content item that 
		// Circular dependencies are detected by disallowing any item to be deferred more than 5 times
		// It's a fairly crude algorithm but it works
		
		$fragmentDefined = array('header' => true, 'footer' => true, 'before' => true, 'after' => true);
		reset($content);
		while(list($k,$v) = each($content)) {
			if(preg_match_all('/\$DefineFragment\(([a-z0-9\-_]+)\)/i', $v, $matches)) {
				foreach($matches[1] as $match) {
					$fragmentName = strtolower($match);
					$fragmentDefined[$fragmentName] = true;
					$fragment = isset($content[$fragmentName]) ? $content[$fragmentName] : "";

					// If the fragment still has a fragment definition in it, when we should defer this item until
					// later.
					if(preg_match('/\$DefineFragment\(([a-z0-9\-_]+)\)/i', $fragment, $matches)) {
						// If we've already deferred this fragment, then we have a circular dependency
						if(isset($fragmentDeferred[$k]) && $fragmentDeferred[$k] > 5) {
							throw new LogicException("GridField HTML fragment '$fragmentName' and '$matches[1]' " . 
								"appear to have a circular dependency.");
						}
						
						// Otherwise we can push to the end of the content array
						unset($content[$k]);
						$content[$k] = $v;
						if(!isset($fragmentDeferred[$k])) {
							$fragmentDeferred[$k] = 1;
						} else {
							$fragmentDeferred[$k]++;
						}
						break;
					} else {
						$content[$k] = preg_replace('/\$DefineFragment\(' . $fragmentName . '\)/i', $fragment,
							$content[$k]);
					}
				}
			}
		}

		// Check for any undefined fragments, and if so throw an exception
		// While we're at it, trim whitespace off the elements
		foreach($content as $k => $v) {
			if(empty($fragmentDefined[$k])) {
				throw new LogicException("GridField HTML fragment '$k' was given content,"
				. " but not defined.  Perhaps there is a supporting GridField component you need to add?");
			}
		}

		$total = count($list);
		if($total > 0) {
			$rows = array();
			foreach($list as $idx => $record) {
				if(!Permission::check('EDIT_GROUPS')) {
					continue;
				}
				$rowContent = '';
				foreach($this->getColumns() as $column) {
					$colContent = $this->getColumnContent($record, $column);
					// A return value of null means this columns should be skipped altogether.
					if($colContent === null) continue;
					$colAttributes = $this->getColumnAttributes($record, $column);
					$rowContent .= FormField::create_tag('td', $colAttributes, $colContent);
				}
				$classes = array('ss-gridfield-item');
				if ($idx == 0) $classes[] = 'first';
				if ($idx == $total-1) $classes[] = 'last';
				$classes[] = ($idx % 2) ? 'even' : 'odd';
				$row = FormField::create_tag(
					'tr',
					array(
						"class" => implode(' ', $classes),
						'data-id' => $record->ID,
						// TODO Allow per-row customization similar to GridFieldDataColumns
						'data-class' => $record->ClassName,
					),
					$rowContent
				);
				$rows[] = $row;
			}
			$content['body'] = implode("\n", $rows);
		} 
		
		// Display a message when the grid field is empty
		if(!(isset($content['body']) && $content['body'])) {
			$content['body'] = FormField::create_tag(
				'tr',
				array("class" => 'ss-gridfield-item ss-gridfield-no-items'),
				FormField::create_tag(
					'td',
					array('colspan' => count($columns)),
					_t('GridField.NoItemsFound')
				)
			);
		}

		// Turn into the relevant parts of a table
		$head = $content['header']
			? FormField::create_tag('thead', array(), $content['header'])
			: '';
		$body = $content['body']
			? FormField::create_tag('tbody', array('class' => 'ss-gridfield-items'), $content['body'])
			: '';
		$foot = $content['footer']
			? FormField::create_tag('tfoot', array(), $content['footer'])
			: '';

		$this->addExtraClass('ss-gridfield field');
		$attrs = array_diff_key(
			$this->getAttributes(), 
			array('value' => false, 'type' => false, 'name' => false)
		);
		$attrs['data-name'] = $this->getName();
		$tableAttrs = array(
			'id' => isset($this->id) ? $this->id : null,
			'class' => 'ss-gridfield-table',
			'cellpadding' => '0',
			'cellspacing' => '0'	
		);

		if($this->getDescription()) {
			$content['after'] .= FormField::create_tag(
				'span', 
				array('class' => 'description'), 
				$this->getDescription()
			);
		}

		return
			FormField::create_tag('fieldset', $attrs, 
				$content['before'] .
				FormField::create_tag('table', $tableAttrs, $head."\n".$foot."\n".$body) .
				$content['after']
			);
	}
}

